package com.sl.discovery.modular;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.sl.discovery.modular.discovery.DbDiscoveryClient;
import com.sl.discovery.modular.discovery.domain.entity.AppServiceInstanceDO;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import lombok.SneakyThrows;
import org.anyline.adapter.init.DefaultEnvironmentWorker;
import org.anyline.data.jdbc.runtime.JDBCRuntimeHolder;
import org.anyline.data.param.ConfigStore;
import org.anyline.data.param.init.DefaultConfigStore;
import org.anyline.entity.DataRow;
import org.anyline.entity.EntitySet;
import org.anyline.metadata.Column;
import org.anyline.metadata.Table;
import org.anyline.metadata.type.init.StandardTypeMetadata;
import org.anyline.proxy.ServiceProxy;
import org.anyline.service.AnylineService;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

public class DatabaseManager {

    private DataSource dataSource;

    private AnylineService anylineService;

    public DatabaseManager(DataSource dataSource) {
        DefaultEnvironmentWorker.start();
        this.dataSource = dataSource;
    }

    private void initAnyLineService() {
        if (ObjectUtil.isNotNull(anylineService)) {
            return;
        }

        synchronized (DbDiscoveryClient.class) {
            if (ObjectUtil.isNotNull(anylineService)) {
                return;
            }
            anylineService = initDb(dataSource);
            createTable(AppServiceInstanceDO.class);
        }

    }


    protected AnylineService initDb(DataSource dataSource) {
        String key = "dbDiscoveryClient-ds";
        JDBCRuntimeHolder.instance().reg(key, dataSource);
        AnylineService anylineService = ServiceProxy.service(key);
        return anylineService;
    }

    public EntitySet<AppServiceInstanceDO> list() {
        initAnyLineService();
        EntitySet<AppServiceInstanceDO> selects = anylineService.selects(getTableName(AppServiceInstanceDO.class), AppServiceInstanceDO.class);

        return selects;
    }


    public String getTableName(Class<?> clazz) {
        jakarta.persistence.Table annotation = AnnotationUtil.getAnnotation(clazz, jakarta.persistence.Table.class);
        return annotation.name();
    }

    public void register(AppServiceInstanceDO appServiceInstanceDO) {
        initAnyLineService();
        EntitySet<AppServiceInstanceDO> selects = anylineService.selects(getTableName(AppServiceInstanceDO.class), AppServiceInstanceDO.class);

        List<AppServiceInstanceDO> list = selects.stream().filter(v -> v.getHost().equals(appServiceInstanceDO.getHost())
                && v.getPort().equals(appServiceInstanceDO.getPort())).toList();

        if (CollUtil.isNotEmpty(list)) {
            anylineService.deletes( getTableName(AppServiceInstanceDO.class), "instance_id", list.stream().map(AppServiceInstanceDO::getInstanceId).distinct().toList());
        }
        EntitySet<AppServiceInstanceDO> dataRow = new EntitySet<>();
        dataRow.add(appServiceInstanceDO);
        anylineService.insert(getTableName(AppServiceInstanceDO.class), dataRow);
    }

    public void deregister(String instanceId) {
        initAnyLineService();
        anylineService.deletes(getTableName(AppServiceInstanceDO.class), "instance_id", Lists.newArrayList(instanceId));
    }

    public AppServiceInstanceDO selectByInstanceId(String instanceId) {
        initAnyLineService();
        ConfigStore configStore = new DefaultConfigStore();
        configStore.and("instance_id", instanceId);
        Object obj = anylineService.select(getTableName(AppServiceInstanceDO.class), AppServiceInstanceDO.class, configStore);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return (AppServiceInstanceDO) obj;
    }

    @SneakyThrows
    private AnylineService createTable(Class<?> clazz) {
        Table table = new Table(getTableName(clazz));

        boolean exists = anylineService.metadata().exists(table);
        //存在就不管了
        if (BooleanUtil.isTrue(exists)) {
            return anylineService;
        }
        Field[] fields = ReflectUtil.getFields(clazz);

        for (Field field : fields) {
            String name = field.getName();
            Class<?> type = field.getType();
            Column column = new Column(StrUtil.toUnderlineCase(name));


            Id antoId = AnnotationUtil.getAnnotation(field, Id.class);
            if (ObjectUtil.isNotNull(antoId)) {
                column.setTypeMetadata(StandardTypeMetadata.BIGINT);
                column.autoIncrement(true);
                column.setPrimaryKey(true);
            } else {

                Lob lob = AnnotationUtil.getAnnotation(field, Lob.class);

                if (type.equals(Date.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.DATETIME);
                } else if (type.equals(Integer.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.INTEGER);
                } else if (type.equals(Long.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.LONG);
                } else {
                    if (ObjectUtil.isNotNull(lob)) {
                        column.setTypeMetadata(StandardTypeMetadata.TEXT);
                    } else {
                        column.setTypeMetadata(StandardTypeMetadata.VARCHAR);
                        column.setLength(250);
                    }
                }
            }
            table.addColumn(column);
        }
        //没有就创建
        anylineService.ddl().create(table);
        return anylineService;
    }
}
